package ldh.im.fxbase.service;

import ldh.im.fxbase.util.ThreadPoolUtil;

import javax.sound.sampled.*;
import java.io.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Consumer;

public class AudioStreamService extends AudioService {

    private static final AudioFormat.Encoding AUDIO_ENCODE = AudioFormat.Encoding.PCM_SIGNED;
    private SourceDataLine sourceDataLine;

    public AudioStreamService(String saveDir) {
        this.saveDir = saveDir;
        initDir();
    }

    public AudioStreamService(String saveDir, int recordTotalTime) {
        this.saveDir = saveDir;
        this.recordTotalTime = recordTotalTime;
        initDir();
    }

    public void startStream() {
        try {
            AudioFormat audioFormat = getAudioFormat();
            DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, audioFormat);
            sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
            sourceDataLine.open(audioFormat);
            sourceDataLine.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void playAudio(byte[] bytes, int length) {
        if (sourceDataLine != null && sourceDataLine.isActive()) {
            sourceDataLine.write(bytes, 0, length);
        }
    }

    public void closeAudio() {
        if (sourceDataLine != null) {
            sourceDataLine.stop();
            sourceDataLine.close();
        }
    }

    @Override
    public AudioFormat getAudioFormat() {
        float sampleRate = 48000;     // 8000,11025,16000,22050,44100
        int sampleSizeInBits = 16;    // 8,16
        int channels = 1;             // 1,2
        int frameSize = 2;
        boolean signed = true;        // true,false
        boolean bigEndian = false;    // true,false
        return new AudioFormat(AUDIO_ENCODE, sampleRate, sampleSizeInBits, channels, frameSize, sampleRate,  bigEndian);
    }

    @Override
    public void playRecord(String file, Consumer<Void> consumer) {
        try {
            AudioFormat audioFormat = getAudioFormat();
            AudioSystem.getSourceDataLine(audioFormat);
            DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, audioFormat);
            SourceDataLine sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
            sourceDataLine.open(audioFormat);
            sourceDataLine.start();
            ThreadPoolUtil.submit(()->{
                try (FileInputStream fileInputStream = new FileInputStream(new File(file))){
                    byte[] bytes = new byte[512];
                    int length = fileInputStream.read(bytes);
                    int fileSize = 0;
                    while (length > 0) {
                        fileSize += length;
                        sourceDataLine.write(bytes, 0, length);
                        length = fileInputStream.read(bytes);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    consumer.accept(null);
                    sourceDataLine.stop();
                    sourceDataLine.close();
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public Runnable getAudioRecordThread() {
        audioFile = saveDir + File.separator + getFileName() + ".pcm";
        String ff = audioFile;
        return ()-> {
            File audioFile = new File(ff);

            FileOutputStream outputStream = null;
            long startTime = System.currentTimeMillis();
            long time = 0;
            try {
                outputStream = new FileOutputStream(audioFile);
                targetDataLine.open(getAudioFormat());
                targetDataLine.start();
                byte[] fragment = new byte[1024];
                while (flag && time <= recordTotalTime * 1000) {
                    int length = targetDataLine.read(fragment, 0, fragment.length);
//                    fragment = AudioUtil.removeNoise(fragment, length);
                    outputStream.write(fragment, 0, length);
                    time = System.currentTimeMillis() - startTime;
                    changeTime(time);
                }
                outputStream.flush();
                stopRecord();
                System.out.println("record time:" + time/100);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                close(outputStream);
            }
        };
    }

    //关闭流
    private void close(FileOutputStream outputStream) {
        try {
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

